package org.karelun.gef.model;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.karelun.gef.helper.ConstantMessages;
import org.karelun.gef.helper.IDConstant;
import org.karelun.gef.property.NodeComboBoxPropertyDescriptor;
import org.karelun.gef.property.PropertyLabelProvider;

public abstract class AbstractConnectionModel extends Element implements IConnectionModel,
		IPropertySource {

	private static final long serialVersionUID = 1L;

	private static final String PROP_NAME = "CONNECTION_NAME"; //$NON-NLS-1$

	private static final String PROP_SOURCE_NODE = "SOURCE_NODE"; //$NON-NLS-1$

	private static final String PROP_TARGET_NODE = "TARGET_NODE"; //$NON-NLS-1$

	public static final String P_BEND_POINT = "_BEND_POINT"; //$NON-NLS-1$

	private Node source, target;

	private List<Point> bendPoints = null;
	
	private List<Node> sourceNodes=null;
	
	private List<Node> targetNodes=null;

	private String name;
	
	public AbstractConnectionModel(){
		super();
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void attachSource() {
		this.source.addsourceConnection(this);
	}

	public void attachTarget() {
		this.target.addtargetConnection(this);
	}

	public void setSource(Node model) {
		source = model;
	}

	public void setTarget(Node model) {
		target = model;
	}

	public Node getTarget() {
		return target;
	}

	public Node getSource() {
		return source;
	}

	public void detachSource() {
		source.removeSourceConnection(this);
	}

	public void detachTarget() {
		target.removeTargetConnection(this);
	}

	public void addBendpoint(int index, Point point) {
		if (bendPoints == null)
			bendPoints = new ArrayList<Point>();
		bendPoints.add(index, point);
		firePropertyChange(P_BEND_POINT, null, null);
	}

	public List<Point> getBendPoints() {
		return bendPoints;
	}

	public void removeBendpoint(int index) {
		bendPoints.remove(index);
		firePropertyChange(P_BEND_POINT, null, null);
	}

	public void replaceBendpoint(int index, Point point) {
		bendPoints.set(index, point);
		firePropertyChange(P_BEND_POINT, null, null);
	}
	
	public DiagramModel getDiagramModel() {
		if(source!=null)
			return source.getDiagram();
		else if(target!=null)
			return target.getDiagram();
		return null;
	}
	
	public void addToDiagram() {
		DiagramModel diagram = getDiagramModel();
		diagram.addConnection(this);
	}
	
	public void removeToDiagram() {
		DiagramModel diagram = getDiagramModel();
		diagram.removeConnection(this);
	}
	
	public Object getEditableValue() {
		return this;
	}

	public IPropertyDescriptor[] getPropertyDescriptors() {
		PropertyDescriptor nameDescriptor = new PropertyDescriptor(PROP_NAME,
				ConstantMessages.Conn_Property_Name);
		nameDescriptor.setLabelProvider(new PropertyLabelProvider(IDConstant.Name_prop));
		
		sourceNodes=getNodes(getTarget());
		NodeComboBoxPropertyDescriptor sourceNodeDesc = new NodeComboBoxPropertyDescriptor(
				PROP_SOURCE_NODE, ConstantMessages.Conn_Property_SourceNodeName, sourceNodes);
		
		targetNodes=getNodes(getSource());
		NodeComboBoxPropertyDescriptor targetNodeDesc =new NodeComboBoxPropertyDescriptor(
				PROP_TARGET_NODE, ConstantMessages.Conn_Property_TargetNodeName, targetNodes);
		
		IPropertyDescriptor[] descriptor = new IPropertyDescriptor[] {
				nameDescriptor, sourceNodeDesc , targetNodeDesc};
		return descriptor;
	}

	private List<Node> getNodes(Node node) {
		DiagramModel diagram = node.getDiagram();
		List<Node> nodes = diagram.getNodes();
		List<Node> list = new ArrayList<Node>();
		for(Node child:nodes){
			if(!child.equals(node))
				list.add(child);
		}
		return list;
	}

	public Object getPropertyValue(Object id) {
		if (PROP_NAME.equals(id.toString()))
			return getName();
		else if (PROP_SOURCE_NODE.equals(id.toString())){
			return sourceNodes.indexOf(getSource());
		}else if (PROP_TARGET_NODE.equals(id.toString())){
			return targetNodes.indexOf(getTarget());
		}
		return null;
	}

	public boolean isPropertySet(Object id) {
		return PROP_NAME.equals(id.toString())
				|| PROP_SOURCE_NODE.equals(id.toString())
				|| PROP_TARGET_NODE.equals(id.toString());
	}

	public void setPropertyValue(Object id, Object value) {
		if(PROP_SOURCE_NODE.equals(id.toString())){
			Integer index=(Integer)value;
			Node node = sourceNodes.get(index);
			setSource(node);
			attachSource();
		}else if(PROP_TARGET_NODE.equals(id.toString())){
			Integer index=(Integer)value;
			Node node = targetNodes.get(index);
			setTarget(node);
			attachTarget();
		}
	}

	public void resetPropertyValue(Object id) {

	}
}
